package com.usbxyz.usb2xxxdemo;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

import com.sun.jna.Pointer;
import com.toomoss.USB2XXX.Lock;
import com.toomoss.USB2XXX.USB2ADC;
import com.toomoss.USB2XXX.USBList;
import com.toomoss.USB2XXX.USB_Device;
import com.usbxyz.usb2xxxdemo.USB2CAN.CANTestActivity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class USBManagerActivity extends AppCompatActivity {
    private static final String ACTION_USB_PERMISSION ="com.usbxyz.USB_PERMISSION";
    //导入库，必须要
    static{
        System.loadLibrary("jnidispatch");
        System.loadLibrary("USB2XXX");
        System.loadLibrary("usb");
    }
    //宏定义
    public static byte USB_REQ_TYPE_STANDARD                 = 0x00;
    public static byte USB_REQ_TYPE_CLASS                    = 0x20;
    public static byte USB_REQ_TYPE_VENDOR                   = 0x40;
    public static byte USB_REQ_TYPE_MASK                     = 0x60;

    public static byte USB_REQ_RECIPIENT_DEVICE              = 0x00;
    public static byte USB_REQ_RECIPIENT_INTERFACE           = 0x01;
    public static byte USB_REQ_RECIPIENT_ENDPOINT            = 0x02;
    public static byte USB_REQ_RECIPIENT_MASK                = 0x03;

    public static byte SEND_ENCAPSULATED_COMMAND              = 0x00;
    public static byte GET_ENCAPSULATED_RESPONSE              = 0x01;
    public static byte SET_COMM_FEATURE                       = 0x02;
    public static byte GET_COMM_FEATURE                       = 0x03;
    public static byte CLEAR_COMM_FEATURE                     = 0x04;
    public static byte SET_LINE_CODING                        = 0x20;
    public static byte GET_LINE_CODING                        = 0x21;
    public static byte SET_CONTROL_LINE_STATE                 = 0x22;
    public static byte SEND_BREAK                             = 0x23;
    public static byte NO_CMD                                 =  (byte)0xFF;
    //以下为自定义命令
    public static byte CMD_SNIFFER_STOP_READ                  = 0x30;
    public static byte CMD_ADC_STOP_READ                      = 0x40;
    public static byte CMD_GET_SERIAL_NUM                     = 0x50;
    public static byte CMD_RESET_DEVICE                       = 0x60;
    public static byte CMD_GET_CANFD_SENDED_NUM               = 0x70;
    public static byte CMD_GET_CANFD_SENDED_MSG               = 0x71;
    public static byte CMD_GET_CANFD_MSG                      = 0x72;
    public static byte CMD_GET_CANFD_DIAGNOSTIC               = 0x73;
    public static byte CMD_GET_CANFD_BUS_ERROR                = 0x74;
    public static byte CMD_WRITE_GPIO                         =  (byte)0x80;
    public static byte CMD_READ_GPIO                          =  (byte)0x81;

    private UsbManager usbManager;
    //private UsbDevice[] usbDevice=new UsbDevice[20];
    public HashMap<Integer,UsbDevice> usbDevMap;
    int DevNum=0;
    private PendingIntent pendingIntent;
    Context context;
    public class USB2XXXDev{
        public int DevHandle;
        public UsbDevice usbDevice;
        public UsbInterface usbInterface=null;
        public UsbEndpoint[] BulkInEndpoint=new UsbEndpoint[8];
        public UsbEndpoint[] BulkOutEndpoint=new UsbEndpoint[8];
        public UsbDeviceConnection connection=null;
        USB2XXXDev(UsbDevice device){
            usbDevice = device;
            usbInterface = usbDevice.getInterface(0);
            if(usbInterface==null){
                return;
            }
            for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
                UsbEndpoint ep = usbInterface.getEndpoint(i);
                // look for bulk endpoint
                if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                    if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
                        BulkOutEndpoint[ep.getEndpointNumber()] = ep;
                    } else {
                        BulkInEndpoint[ep.getEndpointNumber()] = ep;
                    }
                }
                System.out.println(String.format("ep[%d] %d %d %d",i,ep.getType(),ep.getDirection(),ep.getEndpointNumber()));
            }
            System.out.println("usbInterface.getEndpointCount() = "+usbInterface.getEndpointCount());
            connection = usbManager.openDevice(device);
            if(connection == null){
                System.out.println("openDevice error");
                return;
            }
            DevHandle = connection.getFileDescriptor();
            boolean state = connection.claimInterface(usbInterface,true);
            System.out.println("claimInterface state = " + state);
            byte[] buffer = new byte[4];
            int ret = connection.controlTransfer(0x80|USB_REQ_TYPE_VENDOR|USB_REQ_RECIPIENT_INTERFACE,CMD_GET_SERIAL_NUM,0,0,buffer,4,100);
            if(ret == 4) {
                System.out.println("controlTransfer ret = " + ret);
                System.out.println("buffer = 0x" + String.format("%02X",buffer[3])+ String.format("%02X",buffer[2])+ String.format("%02X",buffer[1])+ String.format("%02X",buffer[0]));
                int SerialNumber = (buffer[0]&0xFF) | (((int) buffer[1] << 8)&0xFF00) | (((int) buffer[2] << 16)&0xFF0000) | (((int) buffer[3] << 24)&0xFF000000);
                System.out.println("SerialNumber = " + String.format("0x%08X",SerialNumber));
                DevHandle = SerialNumber;
                USBList.INSTANCE.usb_list_add(DevHandle);
                System.out.println("list len = "+USBList.INSTANCE.usb_list_length());
            }else{
                System.out.println("get SerialNumber ret = " + ret);
            }
        }
    }
    public List<USB2XXXDev> USB2XXXDevList = new ArrayList<USB2XXXDev>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    public int USBScanDev()
    {
        USBList.INSTANCE.usb_list_clear();
        USB2XXXDevList.clear();
        //扫描已经连接的USB设备
        if(usbManager == null){
            System.out.println("usbManager is null");
            return 0;
        }
        HashMap<String, UsbDevice> map = usbManager.getDeviceList();
        System.out.println("map.size = "+map.size());
        for(UsbDevice device : map.values()){
            if(USB_Device.DEV_VID == device.getVendorId() && USB_Device.DEV_PID == device.getProductId()){
                if(!usbManager.hasPermission(device)) {
                    pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
                    usbManager.requestPermission(device, pendingIntent);
                }
                USB2XXXDev mUSB2XXXDev = new USB2XXXDev(device);
                if(mUSB2XXXDev.connection != null) {
                    USB2XXXDevList.add(mUSB2XXXDev);
                }
            }
        }
        return USB2XXXDevList.size();
    }
    public boolean USBInit(Context context){
        this.context = context;
        usbManager = (UsbManager) context.getSystemService(context.USB_SERVICE);
        //注册USB插拔检测服务
        IntentFilter filter = new IntentFilter();
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        filter.addAction(ACTION_USB_PERMISSION);
        filter.setPriority(Integer.MAX_VALUE); //设置级别
        UsbDeviceDetachedBroadcastReceiver usbStateReceiver = new UsbDeviceDetachedBroadcastReceiver();
        context.registerReceiver(usbStateReceiver,filter);
        USBList.INSTANCE.usb_list_init();
        //设置回调函数，必须调用
        USB_Device.INSTANCE.set_scan_dev(scan_dev);
        USB_Device.INSTANCE.set_open_dev(open_dev);
        USB_Device.INSTANCE.set_close_dev(close_dev);
        USB_Device.INSTANCE.set_reset_dev(reset_dev);
        USB_Device.INSTANCE.set_retry_connect_dev(retry_connect_dev);
        USB_Device.INSTANCE.set_del_dead_device(del_dead_device);
        USB_Device.INSTANCE.set_USBBulkWriteData(USBBulkWriteData);
        USB_Device.INSTANCE.set_USBBulkReadData(USBBulkReadData);
        USB_Device.INSTANCE.set_USBCtrlData(USBCtrlData);
        //扫描已经连接的设备
        USBScanDev();
        System.out.println("USBInit Success!"+USB2XXXDevList.size());
        return true;
    }
    //定义回调函数接口
    public USB_Device.p_scan_dev scan_dev = new USB_Device.p_scan_dev(){
        @Override
        public int scan_dev(final Pointer pDevHandle) {
            for(int i=0;i<USB2XXXDevList.size();i++){
                pDevHandle.setInt(i,USB2XXXDevList.get(i).DevHandle);
            }
            return USB2XXXDevList.size();
        }
    };
    public USB_Device.p_open_dev open_dev = new USB_Device.p_open_dev(){
        @Override
        public byte open_dev(int DevHandle) {
            for(int i=0;i<USB2XXXDevList.size();i++){
                if(DevHandle == USB2XXXDevList.get(i).DevHandle){
                    return 1;
                }
            }
            return 0;
        }
    };
    public USB_Device.p_retry_connect_dev retry_connect_dev = new USB_Device.p_retry_connect_dev(){
        @Override
        public byte retry_connect_dev(int DevHandle) {
            return 1;
        }
    };
    public USB_Device.p_close_dev close_dev = new USB_Device.p_close_dev(){
        @Override
        public byte close_dev(int DevHandle) {
            return 1;
        }
    };
    public USB_Device.p_reset_dev reset_dev = new USB_Device.p_reset_dev(){
        @Override
        public byte reset_dev(int DevHandle) {
            return 1;
        }
    };
    public USB_Device.p_del_dead_device del_dead_device = new USB_Device.p_del_dead_device(){
        @Override
        public void del_dead_device() {

        }
    };
    public USB_Device.p_USBBulkWriteData USBBulkWriteData = new USB_Device.p_USBBulkWriteData(){
        @Override
        public int USBBulkWriteData(int DevHandle,int pipenum,final Pointer buffer,int len,int waittime) {
            for(int i=0;i<USB2XXXDevList.size();i++){
                USB2XXXDev Dev=USB2XXXDevList.get(i);
                if(Dev.DevHandle==DevHandle){
                    //byte[] buf = buffer.getByteArray(0,1);
                    int ret = Dev.connection.bulkTransfer(Dev.BulkOutEndpoint[pipenum&0x03],buffer.getByteArray(0,len),len,waittime);
                    //System.out.println("USBBulkWriteData ret = "+ret);
                    if(ret == len){
                        if((len%Dev.BulkOutEndpoint[pipenum&0x03].getMaxPacketSize())==0){
                            Dev.connection.bulkTransfer(Dev.BulkOutEndpoint[pipenum&0x03], buffer.getByteArray(0,len), 0, waittime);
                        }
                        return 0;
                    }else{
                        return -2;
                    }
                }
            }
            return -2;
        }
    };
    public USB_Device.p_USBBulkReadData USBBulkReadData = new USB_Device.p_USBBulkReadData(){
        @Override
        public int USBBulkReadData(int DevHandle,int pipenum,final Pointer buffer,int len,int waittime) {
            for(int i=0;i<USB2XXXDevList.size();i++){
                USB2XXXDev Dev=USB2XXXDevList.get(i);
                if(Dev.DevHandle==DevHandle){
                    byte[] buf=new byte[40960];
                    int ret = Dev.connection.bulkTransfer(Dev.BulkInEndpoint[pipenum&0x03],buf,len,waittime);
                    //System.out.println("USBBulkReadData ret = "+ret);
                    for(int j=0;j<ret;j++){
                        buffer.setByte(j,buf[j]);
                    }
                    return ret;
                }
            }
            return 0;
        }
    };
    public USB_Device.p_USBCtrlData USBCtrlData = new USB_Device.p_USBCtrlData(){
        @Override
        public byte USBCtrlData(int DevHandle,byte request_type, byte bRequest, short wValue, short wIndex,final Pointer data, short wLength, int timeout) {
            for(int i=0;i<USB2XXXDevList.size();i++){
                USB2XXXDev Dev=USB2XXXDevList.get(i);
                if(Dev.DevHandle==DevHandle){
                    int ret = Dev.connection.controlTransfer(request_type,bRequest,wValue,wIndex,data.getByteArray(0,wLength),wLength,timeout);
                    return (ret==wLength)?(byte)1:0;
                }
            }
            return 0;
        }
    };
    //定义USB插拔广播接收器
    class UsbDeviceDetachedBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
                Toast.makeText(context, "Device Detached", Toast.LENGTH_SHORT).show();
                USBScanDev();
            }else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)){
                Toast.makeText(context, "Device Attached", Toast.LENGTH_SHORT).show();
                UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if(!usbManager.hasPermission(usbDevice)){
                    pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
                    usbManager.requestPermission(usbDevice, pendingIntent);
                }
            }else if(intent.getAction().equals(ACTION_USB_PERMISSION)){
                //UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if(intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED,false)){
                    System.out.println("Have get permission");
                    USBScanDev();
                }else{
                    System.out.println("Have not get permission");
                }
            }
        }
    }
}